#pragma once

#include "esp_err.h"
#include "esp_check.h"
#include "esp_log.h"
#include "lvgl.h"
#include "esp_system.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_touch.h"


/**
 * @brief Init configuration structure
 */
typedef struct {
    int task_priority;      /*!< LVGL task priority 优先级*/
    int task_stack;         /*!< LVGL task stack size 栈大小*/
    int task_affinity;      /*!< LVGL task pinned to core (-1 is no affinity) task 固定在核*/
    int task_max_sleep_ms;  /*!< Maximum sleep in LVGL task */
    int timer_period_ms;    /*!< LVGL timer tick period in ms */
} lvgl_port_cfg_t;

/**
 * @brief Rotation configuration
 */
typedef struct {
    bool swap_xy;  /*!< LCD Screen swapped X and Y (in esp_lcd driver) */
    bool mirror_x; /*!< LCD Screen mirrored X (in esp_lcd driver) */
    bool mirror_y; /*!< LCD Screen mirrored Y (in esp_lcd driver) */
} lvgl_port_rotation_cfg_t;

/**
 * @brief Configuration display structure
 */
typedef struct {
    esp_lcd_panel_io_handle_t io_handle;    /*!< LCD panel IO handle */
    esp_lcd_panel_handle_t panel_handle;    /*!< LCD panel handle */
    uint32_t    buffer_size;    /*!< Size of the buffer for the screen in pixels */
    bool        double_buffer;  /*!< True, if should be allocated two buffers */
    uint32_t    hres;           /*!< LCD display horizontal resolution */
    uint32_t    vres;           /*!< LCD display vertical resolution */
    bool        monochrome;     /*!< True, if display is monochrome and using 1bit for 1px */
    lvgl_port_rotation_cfg_t rotation;    /*!< Default values of the screen rotation */

    struct {
        unsigned int buff_dma: 1;    /*!< Allocated LVGL buffer will be DMA capable */
        unsigned int buff_spiram: 1; /*!< Allocated LVGL buffer will be in PSRAM */
    } flags;
} lvgl_port_display_cfg_t;

/**
 * @brief Configuration touch structure
 */
typedef struct {
    lv_disp_t *disp;    /*!< LVGL display handle (returned from lvgl_port_add_disp) */
    esp_lcd_touch_handle_t   handle;   /*!< LCD touch IO handle */
} lvgl_port_touch_cfg_t;


/**
 * @brief LVGL port configuration structure
 *
 */
#define ESP_LVGL_PORT_INIT_CONFIG() \
    {                               \
        .task_priority = 4,       \
        .task_stack = 4096,       \
        .task_affinity = -1,      \
        .task_max_sleep_ms = 500, \
        .timer_period_ms = 5,     \
    }

esp_err_t lvgl_port_init(const lvgl_port_cfg_t *cfg);
lv_disp_t *lvgl_port_add_disp(const lvgl_port_display_cfg_t *disp_cfg);
lv_indev_t *lvgl_port_add_touch(const lvgl_port_touch_cfg_t *touch_cfg);
bool lvgl_port_lock(uint32_t timeout_ms);
void lvgl_port_unlock(void);
void lvgl_port_flush_ready(lv_disp_t *disp);